package com.jboltai.event.chain;


import com.jboltai.config.JBoltAIConfig;
import com.jboltai.event.Event;
import com.jboltai.event.EventErrorType;
import com.jboltai.event.EventState;
import com.jboltai.event.EventType;
import com.jboltai.event.handler.ChainEventHandler;
import com.jboltai.scheduler.EventBus;
import com.jboltai.util.share.AIEventThreadShareData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;

public class Chain extends Event<Chain, Void, ChainEventHandler>{
    static final Logger LOGGER = LoggerFactory.getLogger(JBoltAIConfig.LOGGER_NAME);
    private ChainHandler successHandler;
    private ChainHandler failHandler;
    private ChainHandler startHandler;
    private ChainHandler completeHandler;
    /**
     * publish模式
     */
    static final int MODE_PUBLISH = 1;
    static final int MODE_DISPATCH = 2;

    //todo 线程池，需要组成可配置的
    static ThreadPoolExecutor THEAD_POOL = new ThreadPoolExecutor(
            5,
            20,
            0,
            TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>()
    );


    /**
     * 阻塞执行的锁
     */
    protected CountDownLatch waitLatch = new CountDownLatch(1);
    private ReentrantLock lock = new ReentrantLock();
    /**
     * 事件执行模式
     */
    int mode = 0;

    private ChainData chainData = new ChainData();

    /**
     * 当前正在运行的节点
     */
    private ConcurrentHashMap<String, Object> RUNNING_NODES = new ConcurrentHashMap<>();


    public Chain() {
        super(EventType.CHAIN);
    }

    public ChainHandler getSuccessHandler() {
        return successHandler;
    }

    public void setSuccessHandler(ChainHandler successHandler) {
        this.successHandler = successHandler;
    }

    public ChainHandler getFailHandler() {
        return failHandler;
    }

    public void setFailHandler(ChainHandler failHandler) {
        this.failHandler = failHandler;
    }

    public ChainHandler getStartHandler() {
        return startHandler;
    }

    public void setStartHandler(ChainHandler startHandler) {
        this.startHandler = startHandler;
    }

    public ChainHandler getCompleteHandler() {
        return completeHandler;
    }

    public void setCompleteHandler(ChainHandler completeHandler) {
        this.completeHandler = completeHandler;
    }

    /**
     * 节点
     */
    private List<ChainNode> nodes = new ArrayList<>();


    /**
     * 添加节点
     * @param nodes
     * @return
     */
    public Chain addNodes(ChainNode... nodes) {
        for (ChainNode node : nodes) {
            node.setChain(this);
            if (node.getPrevs() == null) {
                //只有没有前置节点的节点，才能添加到chain中

                //todo 完善，有情况是add完了之后，设置的prev，要不要考虑这种情况的发生
                // 还是规范中 要求用户必须设置好了节点的所有信息后，再add到chain中
                this.nodes.add(node);
            }
        }

        return this;
    }




    /**
     * 发布事件链，所有节点以publish模式运行
     */
    public Chain publish() {
        mode = MODE_PUBLISH;
        EventBus.hold(this);
        start();
        return this;
    }



    /**
     * 发布事件链, 所有节点以dispatch模式运行
     */
    public Chain dispatch() {
        mode = MODE_DISPATCH;
        EventBus.hold(this);
        start();
        return this;
    }

    /**
     * 启动
     */
    private void start() {
        AIEventThreadShareData threadShareData ;
        if (this.getThreadShareData() == null && (threadShareData = AIEventThreadShareData.getShareData()) != null) {
            this.setThreadShareData(threadShareData);
        }
        String preCheckMsg = preCheck();
        if (preCheckMsg != null) {
            this.fail(EventErrorType.PREV_CHECK_NOT_PASS, preCheckMsg);
            return;
        }
        this.setState(EventState.PROCESSING);
        for (ChainNode node : this.nodes) {
            startNode(node);
        }
    }

    /**
     * 开始执行某个节点
     */
    void startNode(ChainNode node) {

        if (node instanceof CommonChainNode
                || node instanceof BooleanChainNode
                || node instanceof IntentionChainNode
                || node instanceof CaseChainNode
        ) {

            if (this.mode == MODE_PUBLISH) {
                THEAD_POOL.execute(node);
                //todo 线程池如何中断某个线程的执行？
            } else {

                Thread thread = new Thread(node);
                thread.start();
                RUNNING_NODES.put(node.getId(), thread);
            }

        } else if (node instanceof EventChainNode) {

            node.run();
            RUNNING_NODES.put(node.getId(), node);

        } else {

            throw new RuntimeException("未提供实现");
        }
    }



    @Override
    public String preCheck() {
        if (nodes.isEmpty()) {
            return "未设置节点";
        }
        return null;
    }



    public ChainData getContext() {
        return chainData;
    }

    /**
     * 获取上下文数据
     * @param key
     * @return
     * @param <T>
     */
    public <T> T getData(String key) {
        return chainData.get(key);
    }

    /**
     * 设置上下文数据
     * @param key
     * @param value
     */
    public void setData(String key, Object value) {
        chainData.put(key, value);
    }

    /**
     * 移除上下文数据
     * @param key
     */
    public void removeData(String key) {
        chainData.remove(key);
    }

    /**
     * 尝试完结
     */
    void tryComplete() {
        try {
            lock.lock();
            if (this.state != EventState.PROCESSING) {
                return;
            }
            boolean allDone = nodes.stream().allMatch(item -> item.state == EventState.SUCCESS || item.state == EventState.FAIL || item.state == EventState.CANCEL);
            if (allDone) {
                this.success(null);
                this.setState(EventState.SUCCESS);
                this.complete();
            }
        } finally {
            lock.unlock();
        }
    }

    @Override
    protected void innerCancelHandle() {

        RUNNING_NODES.forEach((k,v) -> {
            if (v instanceof Thread) {
                try {
                    ((Thread)v).stop();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                ((ChainNode)v).cancel();
            }
        });

    }

    /**
     * 将某个节点从运行中移除
     * @param id
     */
    void removeFromRunning(String id) {
        RUNNING_NODES.remove(id);
    }
}
